#include "RenderableEntity.h"
#include "NeroGame\NComponent.h"
#include "NeroGame\NRenderComponent.h"
#include "NeroEngine\NCamera.h"
#include "Utility.h"
#include "Model.h"

using namespace Graphics;

RenderableEntity::RenderableEntity(void)
	:Game::NGameEntity(),
	 mModel(NULL)
{
	SetPosition(D3DXVECTOR3 (0.0f, 0.0f, 0.0f));
	SetOrientation(D3DXVECTOR3 (0.0f, 1.0f, 0.0f));
	SetDirection(D3DXVECTOR3 (1.0f, 0.0f, 0.0f));
	SetRight(D3DXVECTOR3 (0.0f, 0.0f, 1.0f));
	SetScale(1.0f);

	D3DXMatrixIdentity( &mScaleMatrix );
	D3DXMatrixIdentity( &mWorld );
	D3DXMatrixIdentity( &mWorldViewProjection );
}

RenderableEntity::~RenderableEntity(void)
{
}

void RenderableEntity::Render()
{
	for(unsigned i = 0; i < mComponents.size(); i++)
	{
		if(mComponents[i]->Is("NRenderComponent"))
		{
			Game::NRenderComponent* renderComponet = mComponents[i]->As<Game::NRenderComponent>();
			renderComponet->Render(0.0f);
		}
	}

	if(mModel)
	{
		mModel->Render();
	}
}

void RenderableEntity::Update(float deltaTime)
{
	UpdateMaterial();
	UpdateWorldMatrix();
}

D3DXMATRIX& RenderableEntity::GetViewMatrix()
{
	return mWorldViewProjection;
}

void RenderableEntity::UpdateMaterial()
{
}

void RenderableEntity::UpdateWorldMatrix()
{
	Graphics::D3DDevice* device = GetPlatform()->GetDevice()->As<Graphics::D3DDevice>();
	Engine::NCamera* camera = GetPlatform()->GetCamera();
	//
	D3DXMATRIX cameraView = Utility::NeroToDXD(camera->GetViewMatrix());
	D3DXMATRIX cameraProjection = device->GetProjectionMatrix();
	//
	D3DXVec3Cross(&mRight,&mDirection,&mOrientation);
	D3DXVec3Cross(&mOrientation,&mRight,&mDirection);
	//
	D3DXMATRIX translationMatrix;
	D3DXMatrixTranslation(&translationMatrix, mPosition.x, mPosition.y, mPosition.z);
	//Rotiation matrix
	D3DXMATRIX rotationMatrix = D3DXMATRIX
	(
		mRight.x, mRight.y, mRight.z, 0.0f, 
		mDirection.x, mDirection.y, mDirection.z, 0.0f, 
		mOrientation.x, mOrientation.y, mOrientation.z, 0.0f, 
		0.0f, 0.0f, 0.0f, 1.0f
	);
	//
	D3DXMatrixScaling(&mScaleMatrix, mScale, mScale, mScale);//Scaling matrix
	//
	D3DXMatrixMultiply(&mWorld, &mScaleMatrix,  &rotationMatrix);
	D3DXMatrixMultiply(&mWorld, &mWorld, &translationMatrix);
	//
	D3DXMatrixMultiply(&mWorldViewProjection, &mWorld, &cameraView);
	D3DXMatrixMultiply(&mWorldViewProjection, &mWorldViewProjection, &cameraProjection);
}

Graphics::Model* RenderableEntity::GetModel()
{
	return mModel;
}

void RenderableEntity::Rotate(D3DXVECTOR3 amount)
{
	D3DXMATRIX yRotationMatrix;
	D3DXMatrixRotationY(&yRotationMatrix,amount.y);

	D3DXMATRIX aRotationMatrix;
	D3DXMatrixRotationAxis(&aRotationMatrix,&mRight,amount.x);

	D3DXMatrixMultiply(&yRotationMatrix,&yRotationMatrix,&aRotationMatrix);
	ApplyTransform(yRotationMatrix);
}

void RenderableEntity::ApplyTransform(const D3DXMATRIX& transform)
{
	D3DXVec3TransformNormal(&mDirection,&mDirection,&transform);
	D3DXVec3Normalize(&mDirection,&mDirection);

	D3DXVec3TransformNormal(&mOrientation,&mOrientation,&transform);
	D3DXVec3Normalize(&mOrientation,&mOrientation);

	D3DXVec3Cross(&mRight,&mDirection,&mOrientation);
	D3DXVec3Cross(&mOrientation,&mRight,&mDirection);
}

int RenderableEntity::GetIndexCount()
{
	int indexCount = 0;
	if(mModel)
	{
		indexCount = mModel->GetIndexCount();
	}
	return indexCount;
}